using System;
using System.Collections.Generic;
using System.Text;
using AOT.Game.Misc;
using Assets.Config;
using Cysharp.Threading.Tasks;
using Newtonsoft.Json;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using Wxy.Res.Config;
using Wxy.Res.Net;
using Object = UnityEngine.Object;

namespace Wxy.Res
{
    public enum ResMode
    {
        Local,
        Bundle
    }

    /// <summary>
    /// 资源加载模块
    /// 调试模式本地bundle
    /// 发布模式服务器bundle
    /// 需要先打包生成json配置文件
    /// 1.设计打包策略 ok
    /// 2.做包引用计数 ok
    /// 3.管理包加载和卸载 ok
    /// 4.需要暂存加载好的游戏物体 ok
    /// 5.由于是通过引用计数来计算依赖，那么可能存在循环依赖的问题，需要注意 ok
    /// </summary>
    public class ResMgr : MonoBehaviour
    {
        private ResCore _resCore;
        [SerializeField] private ResMode _resMode;

        public void Awake()
        {
#if !UNITY_EDITOR
            _resMode = ResMode.Bundle;
#else
            _resMode = AssetDatabase.LoadAssetAtPath<ResLoadMode>("Assets/Scripts/AB/ResLoadMode.asset").resMode;
            if (_resMode == null)
            {
                _resMode = ResMode.Bundle;
            }
#endif
            _resCore = new ResCore(_resMode);
        }

        public async UniTask UpdateResAndDll()
        {
            // Bundle模式下
            if (_resMode == ResMode.Bundle)
            {
                Debug.Log("使用bundle模式加载资源");
                bool isNeedUpdateRes = false;
                Manifest manifest2 = null;
                (bool, string) manifestJson1 = Utils.ReadFileFromDisk(ResCfg.LOCAL_MANIFEST);
                // 从资源服务器下载比较文件
                //等待任务完成
                await UniTask.RunOnThreadPool(() =>
                    UpdateResFromServerAndSaveLocal(ResCfg.SERVER_RES + "manifest.json", ResCfg.LOCAL_MANIFEST));
                var manifestJson2 = Utils.ReadFileFromDisk(ResCfg.LOCAL_MANIFEST);
                if (!manifestJson2.Item1)
                {
                    Debug.LogWarning("资源加载出现问题");
                    return;
                }

                manifest2 = JsonConvert.DeserializeObject<Manifest>(manifestJson2.Item2);
                //如果从本地加载成功了
                if (manifestJson1.Item1)
                {
                    Manifest manifest1 = JsonConvert.DeserializeObject<Manifest>(manifestJson1.Item2);
                    if (!manifest1.version.Equals(manifest2.version))
                    {
                        isNeedUpdateRes = true;
                    }
                }
                else
                {
                    isNeedUpdateRes = true;
                }

                List<UniTask> taskList = new();
                if (isNeedUpdateRes)
                {
                    Debug.Log("开始从服务器下载资源");
                    List<ManifestBundle> resPathList = manifest2.bundleList;
                    foreach (var manifestBundle in resPathList)
                    {
                        var serverResPath = ResCfg.SERVER_RES + manifestBundle.name;
                        var localResPath = ResCfg.AB_RES + manifestBundle.name;
                        //unitask多任务下载
                        taskList.Add(UpdateResFromServerAndSaveLocal(serverResPath, localResPath));
                    }

                    //下载热更程序集
                    var serverDllPath = ResCfg.SERVER_RES + "HotUpdate.dll.bytes";
                    var localDllPath = ResCfg.DLL_PATH;
                    taskList.Add(UpdateResFromServerAndSaveLocal(serverDllPath, localDllPath));
                }

                await UniTask.WhenAll(taskList);
            }

            // 编辑模式下
            if (_resMode == ResMode.Local)
            {
                Debug.Log("使用本地模式通过AssetDatabase模式加载资源");
            }
        }

        public Object LoadAsset(string objFilePath, Type type) => _resCore.LoadAsset(objFilePath, type);
        public T LoadAsset<T>(string objFilePath) where T : Object => (T)_resCore.LoadAsset(objFilePath, typeof(T));
        public void UnLoadAsset(string objFilePath) => _resCore.UnLoadAsset(objFilePath);
        public void GC(double maxUseSecond = 10, bool unloadAllLoadedObjects = false) =>
            _resCore.GC(maxUseSecond, unloadAllLoadedObjects);
#if UNITY_EDITOR
        public void ShowInfo() => _resCore.ShowInfo();
#endif

        #region 内部实现

        private async UniTask UpdateResFromServerAndSaveLocal(string serverResPath, string localPath)
        {
            byte[] downloadResAsync = await ResNetUtils.DownloadResAsync(serverResPath);
            Utils.SaveFileToDisk(downloadResAsync, localPath);
        }

        #endregion
    }
}